﻿using System.Linq.Expressions;
using Abc.Application.Dtos;
using Abc.Domain.Users;
using Abc.EFCore;
using AutoMapper;
using JwtBearer;
using MD5Encrypt;
using Microsoft.EntityFrameworkCore;

namespace Abc.Application.Users;

public class UserService : IUserService
{
    private readonly DefaultDbContext _dbContext;
    private readonly IMapper _mapper;
    private DbSet<User> Users => _dbContext.Set<User>();

    public UserService(DefaultDbContext dbContext, IMapper mapper)
    {
        _dbContext = dbContext;
        _mapper = mapper;
    }

    /// <summary>
    /// 注册用户
    /// </summary>
    /// <param name="account">账号</param>
    /// <param name="password">密码</param>
    /// <param name="name">姓名</param>
    /// <param name="mobile">手机号码</param>
    /// <param name="birthday">生日 yyyy-MM-dd</param>
    /// <returns>创建结果</returns>
    public async Task<UserDto> RegisterAsync(string account, string password, string name, string mobile,
        DateTime birthday)
    {
        var salt = Guid.NewGuid().ToString();
        var user = new User(account, Md5Encryptor.Encrypt(password + salt), salt, name, mobile)
        {
            Birthday = birthday
        };
        await Users.AddAsync(user);
        await _dbContext.SaveChangesAsync();

        return _mapper.Map<UserDto>(user);
    }

    /// <summary>
    /// 分页查询
    /// </summary>
    public async Task<PagedResultDto<UserDto>> GetPagedListAsync(string? account, string? name, string? mobile,
        DateTime? birthday,
        int pageIndex = 1, int pageSize = 10)
    {
        var query = Users.AsQueryable()
            .WhereIf(account.IsNotNullOrWhiteSpace(), user => user.Account.Contains(account!))
            .WhereIf(name.IsNotNullOrWhiteSpace(), user => user.Name.Contains(name!))
            ;
        var total = await query.CountAsync();
        var users = await query
            .Skip((pageIndex - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();
        var items = _mapper.Map<List<UserDto>>(users);
        return new(total, items);
    }

    public async Task<bool> CheckLoginAsync(string account, string password)
    {
        var user = await GetByUserNameAsync(account);
        var passwordEncrypt = Md5Encryptor.Encrypt(password + user.Salt);
        if (user.Password == passwordEncrypt)
        {
            return true;
        }
        else
        {
            throw new PasswordIncorrectException(account);
        }
    }

    public async Task<UserInfoDto> GetUserInfo(string account)
    {
        var user = await Users.FirstOrDefaultAsync(user => user.Account == account) ??
                   throw new UserNotFoundException(account);

        return _mapper.Map<User,UserInfoDto>(user);
    }

    /// <summary>
    /// 根据账号查询用户
    /// </summary>
    /// <param name="account">账号</param>
    /// <returns>用户对象</returns>
    /// <exception cref="UserNotFoundException">异常：用户未找到</exception>
    private async Task<User> GetByUserNameAsync(string account)
    {
        var user = await Users.AsQueryable().FirstOrDefaultAsync(user => user.Account == account);
        if (user is null)
        {
            throw new UserNotFoundException(account);
        }

        return user;
    }
}

public class UserNotFoundException : Exception
{
    public UserNotFoundException(string account) : base($"未找到用户: {account}")
    {
    }
}

public class PasswordIncorrectException : Exception
{
    public PasswordIncorrectException(string account) : base($"密码错误: {account}")
    {
    }
}

public static class CommentTypeExtensions
{
    public static bool IsNotNullOrWhiteSpace(this string? value) => !string.IsNullOrWhiteSpace(value);
}

public static class QueryableExtensions
{
    public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> query, bool condition,
        Expression<Func<TSource, bool>> predicate)
    {
        if (condition)
        {
            query = query.Where(predicate);
        }

        return query;
    }
}
 